﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;

using EnvDTE;
using EnvDTE80;
using DoxygenBrowserAddin.Data;

namespace DoxygenBrowserAddin.Controller
{
    public class DoxAddinController
    {
        #region Constants
        
        public const string DOXDOC_EXTENSION = ".doxproj";
        private const string CMD_NAVIGATEFROMHERE = "NavigateFromHere";
        private const string CMD_DOXYGENWINDOW = "DoxygenWindow";
        private const string CMD_DOXYGENCONFIG = "DoxygenConfig";

        #endregion

        #region Attributes

        private DoxygenConfig _doxConfig;

        private CmdShowDoxBrowser _cmdShowDoxBrowser;
        private CmdNavigateFromHere _cmdNavigateFromHere;
        private CmdDoxygenConfig _cmdDoxygenConfig;

        private List<AddInCommand> _lstCommands;

        private TokenDictionary _tokenDictionary;
        private SolutionEvents _solutionEvents;

        // Declare the variables at the class scope
        private Events2 _events;

        #endregion

        #region Events
        
        public event EventHandler DoxygenConfigChanged;

        #endregion

        #region Properties
        
        private Views.DoxygenBrowser _doxygenBrowserControl;
        public Views.DoxygenBrowser BrowserView
        {
            get { return _doxygenBrowserControl; }
        }

        private Window _toolWindow;
        public Window ToolWindow { get { return _toolWindow; } }

        private DTE2 _applicationObject;
        public DTE2 Application { get { return _applicationObject; } }

        private AddIn _addInInstance;
        public AddIn AddInInstance { get { return _addInInstance; } }

        public ReadOnlyCollection<AddInCommand> Commands
        {
            get { return new ReadOnlyCollection<AddInCommand>(_lstCommands); }
        }

        public TokenDictionary TokenDictionary
        {
            get { return _tokenDictionary; }
            set { _tokenDictionary = value; }
        }

        public bool IsDictionaryLoaded
        {
            get
            {
                return _tokenDictionary != null;
            }
        }

        private string _doxygenConfigPath;
        public string DoxygenConfigPath
        {
            get { return _doxygenConfigPath; }
            set { _doxygenConfigPath = value; }
        }

        #endregion

        #region Public Methods

        public void Initialize(DTE2 applicationObject, AddIn addInInstance)
        {
            _applicationObject = applicationObject;
            _addInInstance = addInInstance;

            _lstCommands = new List<AddInCommand>();

            _cmdNavigateFromHere = new CmdNavigateFromHere(CMD_NAVIGATEFROMHERE, this);
            _lstCommands.Add(_cmdNavigateFromHere);

            _cmdShowDoxBrowser = new CmdShowDoxBrowser(CMD_DOXYGENWINDOW, this);
            _lstCommands.Add(_cmdShowDoxBrowser);

            _cmdDoxygenConfig = new CmdDoxygenConfig(CMD_DOXYGENCONFIG, this);
            _lstCommands.Add(_cmdDoxygenConfig);

            createMainView();
            createHandlers();
        }

        public AddInCommand GetCommand(string strCommandName)
        {
            foreach (AddInCommand command in _lstCommands)
            {
                if (command.CommandName == strCommandName)
                {
                    return command;
                }
            }
            return null;
        }

        #endregion

        private void createHandlers()
        {
            // Use it somewhere in code
            _events = (Events2)_applicationObject.Events;

            _solutionEvents = _events.SolutionEvents;

            _solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(this.OnSolutionOpened);
            _solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(this.OnAfterClosing);
        }

        private void Execute(AddInCommand addinCommand)
        {
            vsCommandStatus status = vsCommandStatus.vsCommandStatusEnabled;
            object CommandText = null;
            _cmdShowDoxBrowser.QueryStatus(vsCommandStatusTextWanted.vsCommandStatusTextWantedNone, ref status, ref CommandText);
            if ((status & vsCommandStatus.vsCommandStatusEnabled) != 0)
            {
                object varIn = null;
                object varOut = null;
                _cmdShowDoxBrowser.Execute(vsCommandExecOption.vsCommandExecOptionDoDefault, ref varIn, ref varOut);
            }
        }

        private void createMainView()
        {
            object programmableObject = null;

            string guidString = "{9FFC9D9B-1F39-4763-A2AF-66AED06C799A}";
            Windows2 windows2 = (Windows2)_applicationObject.Windows;
            Assembly asm = Assembly.GetExecutingAssembly();
            _toolWindow = windows2.CreateToolWindow2(_addInInstance,
                                                     asm.Location,
                                                     typeof(DoxygenBrowserAddin.Views.DoxygenBrowser).FullName,
                                                     "Doxygen",
                                                     guidString,
                                                     ref programmableObject);
            _toolWindow.Visible = true;
            _doxygenBrowserControl = (Views.DoxygenBrowser)_toolWindow.Object;
            _doxygenBrowserControl.SetController(this);
            _doxygenBrowserControl.NavigateHome();
            _toolWindow.IsFloating = false;
        }

        public void OnShowDoxBrowser()
        {
            _doxygenBrowserControl.NavigateHome();
            _toolWindow.Visible = true;
        }

        public DoxygenConfig DoxygenConfig
        {
            get { return _doxConfig; }
            set
            {
                _doxConfig = value;
                OnDoxygenConfigChanged();

            }
        }

        public void OnSolutionOpened()
        {
            if (DoxygenConfig != null)
            {
                clearProject();
            }

            string strDoxConfigFile = getDoxConfigPathFromSolution(_applicationObject.Solution.FullName);
            FileInfo fileInfo = new FileInfo(strDoxConfigFile);
            if (fileInfo.Exists)
            {
                if (openDoxygenConfigFile(fileInfo.FullName))
                {
                    CreateTokenDictionary();
                    _doxygenBrowserControl.NavigateHome();

                }
            }
        }

        private bool openDoxygenConfigFile(string strDoxConfigPath)
        {
            DoxygenConfigPath = strDoxConfigPath;
            DoxygenConfig doxygenConfig = new DoxygenConfig();
            doxygenConfig.Load(strDoxConfigPath);
            this.DoxygenConfig = doxygenConfig;
            return true;
        }

        private string getDoxConfigPathFromSolution(string strSolutionFullPath)
        {
            FileInfo solutionFileInfo = new FileInfo(strSolutionFullPath);
            string strDirectoryPath = solutionFileInfo.Directory.FullName;

            string strDoxProjFileName = Path.GetFileNameWithoutExtension(strSolutionFullPath) + DOXDOC_EXTENSION;

            string strResult = Path.Combine(strDirectoryPath, strDoxProjFileName);
            return strResult;
        }

        private void clearProject()
        {
            DoxygenConfig = null;
            TokenDictionary = null;
            DoxygenConfigPath = string.Empty;
        }

        public void OnAfterClosing()
        {
            clearProject();
        }

        public void CreateTokenDictionary()
        {
            string strDocFullPath = GetDoxHtmlDirectory();
            string strTokenFilePath = Path.Combine(strDocFullPath, "tokens.xml");

            _doxygenBrowserControl.StartIndexing(strTokenFilePath);
            TokenDictionaryLoader loader = new TokenDictionaryLoader();
            loader.ProgressChangedEvent += new ProgressChangedEventHandler(loader_ProgressChangedEvent);
            using (StreamReader sr = new StreamReader(strTokenFilePath))
            {
                loader.Process(sr.BaseStream);
            }
            TokenDictionary = loader.TokenDictionary;
            _doxygenBrowserControl.EndIndexing(strTokenFilePath);

        }

        void loader_ProgressChangedEvent(object sender, ProgressChangedEventArgs e)
        {
            _doxygenBrowserControl.ProgressIndexing(e.ProgressPercentage);
        }

        public string GetDoxHtmlDirectory()
        {
            string strDirectoryName = Path.GetDirectoryName(DoxygenConfigPath);
            string strDoxHtmlPath = string.Empty;

            if (DoxygenConfig != null)
            {
                strDoxHtmlPath = DoxygenConfig.DoxHtmlPath;
            }
            return Path.Combine(strDirectoryName, strDoxHtmlPath);
        }

        public DoxygenConfig CreateDoxConfig(string strDoxConfigPath)
        {
            DoxygenConfigPath = strDoxConfigPath;
            DoxygenConfig doxygenConfig = new DoxygenConfig();
            doxygenConfig.Save(strDoxConfigPath);
            DoxygenConfig = doxygenConfig;

            return doxygenConfig;
        }

        public void CheckSolution()
        {
            if ((_applicationObject.Solution != null) &&
              _applicationObject.Solution.IsOpen)
            {
                OnSolutionOpened();
            }
        }

        internal void OnDoxygenConfigChanged()
        {
            if (DoxygenConfigChanged != null)
            {
                DoxygenConfigChanged(this, EventArgs.Empty);
            }
        }
    }
}
